package main

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"os"
	"regexp"
	"strings"
)

var buf bytes.Buffer

func ParseComment(varName string, comment string) (httpCode string, desc string) {
	// ErrUserNotFound - 404: User not found.
	reg := regexp.MustCompile(`\w\s*-\s*(\d{3})\s*:\s*([A-Z].*)\s*\.\n*`) // \w:表示任意字母和下划线 \s:匹配空格 *:匹配零次到多次 \n:换号 \.:转义.
	if !reg.MatchString(comment) {
		return "500", "Internal Server Error"
	}
	groups := reg.FindStringSubmatch(comment)
	if len(groups) != 3 { // 整个 1个分组  (\d{3}) 1个分组  ([A-Z].*) 1个分组
		return "500", "Internal Server Error"
	}
	return groups[1], groups[2]
}

func genDecl(decl *ast.GenDecl) { // ast.GenDecl表示除函数以外的所有导入声明，即import、const、var、type
	//ast.GenDecl(decl)
	for _, s := range decl.Specs { // 遍历 const 下的 所有字段
		v := s.(*ast.ValueSpec)        // 断言 因为是 interface 类型
		for _, name := range v.Names { // 遍历 Values 的所有字段 可以是写法 ErrUserNotFound2, ErrUserNotFound3 = 1, 2
			var comment string
			if v.Doc != nil && v.Doc.Text() != "" { // 如果文档注释不为空 或 注释内容不为空
				comment = v.Doc.Text()
			} else if c := v.Comment; c != nil && len(c.List) == 1 { // 否则取 行注释
				comment = c.Text()
			}
			httpCode, desc := ParseComment(name.Name, comment)
			fmt.Fprintf(&buf, "\tregister(%s, %s, \"%s\")\n", name.Name, httpCode, desc)
			//fmt.Println(name.Name, "|", httpCode, "|", desc)
		}
	}
}

func main() {
	fileName := "C:/Users/CZC/Desktop/go-mxshop/GoStart/p_generate/code/enum.go"

	file, err := parser.ParseFile(token.NewFileSet(), fileName, nil, parser.ParseComments)
	if err != nil {
		panic(err)
	}

	fmt.Fprintf(&buf, "// Code generated by \"codegen %s\"; DO NOT EDIT.\n", strings.Join(os.Args[1:], "")) // os.Args[1:] 获取 运行脚本携带的参数
	fmt.Fprintf(&buf, "\n")
	fmt.Fprintf(&buf, "package %s\n", "code")
	fmt.Fprintf(&buf, "\n")
	fmt.Fprintf(&buf, "func init() {\n")
	genDecl(file.Decls[1].(*ast.GenDecl))
	fmt.Fprintf(&buf, "}\n")

	src := []byte(buf.String())
	os.WriteFile("C:/Users/CZC/Desktop/go-mxshop/GoStart/p_generate/code/code_generated.go", src, 0o600)
	if err != nil {
		panic(err)
	}
}
